/*
 * (c) 2014 Virtusa Corporation.
 * All Rights Reserved
 */
package ead.cs.web.controller;

import ead.cs.domain.*;
import ead.cs.domain.workflow.Status;
import ead.cs.service.PaymentService;
import ead.cs.service.ShipScheduleService;
import ead.cs.service.ShipmentService;
import ead.cs.service.workflow.StateMachineHandler;
import ead.cs.web.utils.Constants;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.Set;

/**
 * @author cjayawickrema
 */
@Controller
public class ScheduleController {

    private static final Logger LOGGER = Logger.getLogger(ScheduleController.class);

    @Autowired
    private ShipScheduleService scheduleService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private StateMachineHandler stateMachineHandler;

    @Autowired
    private ShipmentService shipmentService;

    @RequestMapping(method = RequestMethod.GET, value = "/searchSchedule")
    public String searchSchedule(
            @RequestParam("arrivalPort") String arrivalPort,
            @RequestParam("departurePort") String departurePort,
            @RequestParam("startDate") @DateTimeFormat(pattern = "dd/MM/yyyy") Date startDate,
            @RequestParam("endDate") @DateTimeFormat(pattern = "dd/MM/yyyy") Date endDate,
            Model model,
            HttpServletRequest request) {

        model.addAttribute("schedule", scheduleService.getSchedule(arrivalPort, departurePort, startDate, endDate));
        return "scheduleList";
    }

    @RequestMapping(method = RequestMethod.POST, value = "/declareShipment")
    public String declareShipment(
            @RequestParam("shipmentRef") String shipId,
            Model model,
            HttpServletRequest request) {
        ShipSchedule item = scheduleService.getScheduleItem(shipId);
        model.addAttribute("scheduleItem", item);
        request.getSession().setAttribute("schedule", item);

        return "shipmentDeclaration";
    }

    @RequestMapping(method = RequestMethod.POST, value = "/declare")
    public String saveDeclaration(
            Model model,
            HttpServletRequest request) {

        ShipSchedule schedule = (ShipSchedule) request.getSession().getAttribute("schedule");

        Person exporter = new Person();
        exporter.setAddress(request.getParameter("address"));
        exporter.setCountry(request.getParameter("country"));
        exporter.setEmail(request.getParameter("email"));
        exporter.setFirstName(request.getParameter("firstName"));
        exporter.setLastName(request.getParameter("lastName"));
        exporter.setPhone(request.getParameter("phone"));
        exporter.setTaxNumber(request.getParameter("taxNumber"));
        exporter.setEmailNotification(!StringUtils.isEmpty(request.getParameter("emailNotification")));
        exporter.setSmsNotification(!StringUtils.isEmpty(request.getParameter("smsNotification")));

        Person importer = new Person();
        importer.setFirstName(request.getParameter("recFirstName"));
        importer.setLastName(request.getParameter("recLastName"));
        importer.setPhone(request.getParameter("recPhone"));
        importer.setEmail(request.getParameter("recEmail"));

        Declaration declaration = new Declaration();
        declaration.setCategory(request.getParameter("category"));
        declaration.setContainerType(request.getParameter("containerType"));
        declaration.setDetails(request.getParameter("shipmentDetails"));
        declaration.setExporter(exporter);
        declaration.setHeight(NumberUtils.toDouble(request.getParameter("height")));
        declaration.setWidth(NumberUtils.toDouble(request.getParameter("width")));
        declaration.setWeight(NumberUtils.toDouble(request.getParameter("weight")));
        declaration.setLength(NumberUtils.toDouble(request.getParameter("length")));
        declaration.setImporter(importer);
        declaration.setInflammable("on".equalsIgnoreCase(request.getParameter("inflammable")));
        declaration.setPerishable("on".equalsIgnoreCase(request.getParameter("perishable")));
        declaration.setSchedule(schedule);

        final HttpSession session = request.getSession();
        session.setAttribute("declaration", declaration);

        final double amount = Constants.COST_FACTOR * declaration.getSchedule().getDistance() * declaration.getHeight() * declaration.getLength() * declaration.getWeight() * declaration.getWidth();
        model.addAttribute("amount", amount);
        session.setAttribute("amount", amount);

        return "payment";
    }

    @RequestMapping(method = RequestMethod.POST, value = "/pay")
    public String pay(
            Model model,
            HttpServletRequest request) {
        HttpSession session = request.getSession();
        Declaration declaration = (Declaration) session.getAttribute("declaration");
        Payment payment = new Payment();
        payment.setAmount((Double) session.getAttribute("amount"));
        payment.setCardHolderName(request.getParameter("name"));
        payment.setCardNumber(request.getParameter("cardNumber"));
        payment.setCardType(request.getParameter("cardType"));
        payment.setCvcNumber(request.getParameter("cvc"));
        payment.setDate(new Date());
        payment.setDeclaration(declaration);
        payment.setExpiry(request.getParameter("expiryDate"));
        paymentService.save(payment);

        //declare shipment with SCHEDULED state
        Shipment shipment = new Shipment();
        shipment.setDeclaration(declaration);
        shipment.setPayment(payment);
        Shipment savedShipment = shipmentService.save(shipment);

        stateMachineHandler.execute(Status.SCHEDULED, savedShipment.getId());

        // clear session
        session.removeAttribute("amount");
        session.removeAttribute("declaration");
        session.removeAttribute("schedule");

        model.addAttribute("payment", payment);

        return "receipt";
    }

    @RequestMapping(method = RequestMethod.GET, value = "/schedule")
    public String redirectSchedule() {
        LOGGER.info("redirect to schedule");
        return "schedule";
    }

    @ModelAttribute(value = "departurePorts")
    public Set<String> departurePorts() {
        return scheduleService.findDeparturePorts();
    }

    @ModelAttribute(value = "arrivalPorts")
    public Set<String> arrivalPorts() {
        return scheduleService.findArrivalPorts();
    }

}
